package clasificador.redneuronal;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import utils.Logger;
import clasificador.redneuronal.neurona.GrupoNeuronasSoftmax;
import clasificador.redneuronal.neurona.Neurona;
import clasificador.redneuronal.neurona.NeuronaSigmoide;
import clasificador.redneuronal.neurona.NeuronaSoftmax;
import datos.AtributoFinito;
import datos.MuestraClasificada;

public class PerceptronMulticapa<Clase> extends RedNeuronal<Clase> {
	private int neuronasOcultas;
	/* Indica tantas neuronas ocultas como clases */
	private boolean cNeuronasOcultas;
	/* Indica tantas neuronas ocultas como entradas */
	private boolean kNeuronasOcultas;
	
	public PerceptronMulticapa(MuestraClasificada<Clase> datosEntrenamiento,
			Map<String, Object> parametros) {
		super(datosEntrenamiento, parametros);
	}

	@Override
	protected Set<Neurona> generarRed(
			MuestraClasificada<Clase> datosEntrenamiento) {		
		AtributoFinito<Clase> clase = (AtributoFinito<Clase>)datosEntrenamiento.getClase();
		
		int n = neuronasOcultas;
		
		if(cNeuronasOcultas) n = clase.getRango().size();
		if(kNeuronasOcultas) n = datosEntrenamiento.getAtributos().size() - 1;		
		
		Set<InputSignal> inputs = this.createInputs(datosEntrenamiento);	
		
		Map<Clase,Neurona> outs = new HashMap<>();
		Set<Neurona> neuronas = new HashSet<>();	
		Set<Neurona> neuronasOcultas = new HashSet<>();
	
		/* Capa oculta */
		for(int i = 0; i < n; i++)
		{
			NeuronaSigmoide miNeurona = new NeuronaSigmoide();
			
			for(InputSignal in: inputs)
			{
				miNeurona.linkBack(in);
			}
			
			neuronas.add(miNeurona);
			neuronasOcultas.add(miNeurona);
		}
		
		/* Capa de salida */
		GrupoNeuronasSoftmax grupo = new GrupoNeuronasSoftmax();		
		for(Clase c: clase.getRango())
		{		
			NeuronaSigmoide miNeurona = new NeuronaSigmoide();
			//miNeurona.setGrupo(grupo);
			
			for(Neurona no: neuronasOcultas)
			{
				miNeurona.linkBack(no);
			}
			
			neuronas.add(miNeurona);
			outs.put(c,miNeurona);			
		}
		
		this.createOutputs(datosEntrenamiento,outs);
		
		return neuronas;	
	}

	@Override
	protected void inicializarParametros(Map<String,Object> parametros)
	{
		super.inicializarParametros(parametros);
		
		neuronasOcultas = 5;
		kNeuronasOcultas = false;
		cNeuronasOcultas = false;
		
		if(parametros.get("neuronasOcultas") != null) neuronasOcultas = (Integer)parametros.get("neuronasOcultas");
		if(parametros.get("cNeuronasOcultas") != null) cNeuronasOcultas = (Boolean)parametros.get("cNeuronasOcultas");
		if(parametros.get("kNeuronasOcultas") != null) kNeuronasOcultas = (Boolean)parametros.get("kNeuronasOcultas");
	}
}
